import datetime

from ctaBase import *
from ctaTemplate import *
from indicators import Indicators
from utils import MinKLineGenerator


class My_RSI_V1(CtaTemplate):
    """RSI指标策略version1.0版本  单周期交易策略
        修复问题： 
            1 启动策略，会找不到历史数据导致程序信号异常
            2.k线周期管理
            3.当前文件多周期k线数据不正确  需要验证
            4.相同的交易信号只交易一次
            5.下单逻辑
    """
    auther = '尘心|wx:17630013170'
    className = 'My_RSI_V1'

    def __init__(self):
        super().__init__()

        # 参数映射表
        self.paramMap = {
            'kline_style': 'k线周期',
            'tradetype': '交易方向', #L 多(买点入场，卖点出场) S 空(卖点入场，买点出场)
            'order_volume': '下单手数',
            'volume_num': '总手数',
            'exchange': '交易所',
            'vtSymbol': '合约代码',
        }

        # 变量映射表
        self.varMap = {
            'trading': '交易中',
            'pos': '持仓',
        }
        
        # RSI参数及区间
        self.R = 6
        # self.S = 12
        # self.I = 24
        self.rup = 80
        self.rdm = 20

        self.widgetClass = KLWidget
        self.widget: KLWidget = None
        self.indicators: Indicators = None
        self.kline_generator: MinKLineGenerator = None

         # 策略参数
        self.exchange = ""
        self.vtSymbol = ""
        self.tradetype = 'L' #交易方向
        self.order_volume = 1  # 下单手数
        self.volume_num = 10  # 下单手数
        self.kline_style = "M1" # K 线类型, 具体看 core.pyi 中的 KLineStyle 定义
        self.pay_up = 0 # 超价, 买 + 卖 -

        # 参数变量
        self.current_rsi = 0  # 当前N分钟 K 线rsi数值
        self.prev_rsi = 0  # 上一根N分钟 K 线rsi数值

        #交易状态
        self.trading = False


    def onTick(self, tick: TickData):
        """收到行情TICK推送"""
        super().onTick(tick)

        # 过滤涨跌停和集合竟价
        if tick.lastPrice or tick.askPrice1 or tick.bidPrice1:
            self.kline_generator.tick_to_kline(tick)

    def onInit(self):
        """程序初始化""" 
        self.output('------------程序初始化onInit-----------')
        super().onInit()

     
    def onStart(self):
        """策略启动""" 
        self.output('------------策略启动onStart-----------')

        #获取k线数据
        self.kline_generator = MinKLineGenerator(
            real_time_callback=self.real_time_callback,
            callback=self.callback,
            exchange=self.exchange,
            instrument=self.vtSymbol,
            style=self.kline_style
        )

        # 获取持仓数据 Todo
        position = self.get_position(instrument=self.vtSymbol)
        self.output('合约总持仓:',position.position,'合约净持仓:',position.net_position,'总持仓可平仓数量:',position.long.position_close)

        super().onStart()



    def real_time_callback(self, kline: KLineData) -> None:
        """使用收到的实时推送 K 线来计算指标并更新线图"""
        # self.calc_indicator()

    
    def callback(self, kline: KLineData) -> None:
        """接受 K 线回调"""    
        # self.output('获取k线数据：',kline.close,kline.datetime)
        self.calc_indicator()

        self.calc_signal(kline)

        self.exec_signal()
        self.putEvent()


    def calc_indicator(self) -> None:
        """计算指标数据"""
        current_arr = self.indicators.rsi(self.R,array=True)
        # self.output('当前rsi参数值:', current_arr[-1],current_arr[-2])
        self.current_rsi, self.prev_rsi = round(current_arr[-1],2), round(current_arr[-2],2)
 


    def calc_signal(self, kline: KLineData) -> None:
        """计算交易信号"""

        # 交易信号
        self.buy_signal = (self.current_rsi > self.rdm) & (self.prev_rsi <= self.rdm)
        self.short_signal = (self.current_rsi < self.rup) & (self.prev_rsi >= self.rup)
        # 交易价格
        self.long_price = kline.close  #做多操作时的买入价格
        self.short_price = kline.close #做空操作时的卖出价格
        # if self.buy_signal or self.short_signal: 
        #     # self.output(kline.__dict__)
        #     self.output(self.kline_style + 'RSI交易信号：','buy:',self.buy_signal,'short:',self.short_signal,'rsi值:',self.current_rsi,'上一分钟的值:',self.prev_rsi,'当前价格:',kline.close,'交易时间',kline.datetime)

    def exec_signal(self) -> None:
        """简易交易信号执行
            1 空仓: 如果是看多方向  则买入开仓;如果是看空方向,则卖出开仓。
            2 多头：如果是看多方向，并且是买入信号则买入开仓，如果是卖出信号则卖出平仓;如果方向是看空， 则卖出平仓
            3 空头：如果是看空方向, 并且是卖出信号则卖出开仓，如果是买入信号则买入平仓;如果方向是看多,  则买入平仓
        """
        position = self.get_position(self.vtSymbol)

        # 挂单未成交
        if self.orderID is not None:
            self.cancelOrder(self.orderID)

        if position.net_position == 0:  #: 当前无仓位
            # 买开，卖开
            if self.short_signal and self.tradetype == 'S':
                if self.trading is False:
                    return

                self.orderID = self.short(
                    price=(price := self.short_price - self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'卖出开仓信号价格: {price}')

            elif self.buy_signal and self.tradetype == 'L':

                if self.trading is False:
                    return

                self.orderID = self.buy(
                    price=(price := self.long_price + self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'买入开仓信号价格: {price}')

        elif position.net_position > 0: #: 持有多头仓位
            if self.tradetype == 'L' and self.buy_signal:  

                if self.trading is False:
                    return     
                         
                # 判断总持仓数量
                if position.net_position < self.volume_num:
                    self.orderID = self.buy(
                        price=(price := self.long_price + self.pay_up),
                        volume=self.order_volume
                    )
                    self.output(f'买入开仓信号价格: {price}')
                else:
                    self.output(f'买入开仓持仓数量已达到最大值')

            elif (self.tradetype == 'L' and self.short_signal) or self.tradetype == 'S':

                if self.trading is False:
                    return

                self.orderID = self.auto_close_position(
                    price=(price := self.short_price - self.pay_up),
                    volume=position.net_position,
                    symbol=self.vtSymbol,
                    exchange=self.exchange,
                    order_direction="sell"
                )
                self.output(f'卖出平仓信号价格: {price}')

        elif position.net_position < 0: #: 持有空头仓位
            if self.tradetype == 'S' and self.short_signal:
                if self.trading is False:
                    return
                  # 判断总持仓数量
                if abs(position.net_position) < self.volume_num:
                    self.orderID = self.short(
                        price=(price := self.short_price - self.pay_up),
                        volume=self.order_volume
                    )
                    self.output(f'卖出开仓信号价格: {price}')

            elif (self.tradetype == 'S' and self.buy_signal) or self.tradetype == 'L':  
                if self.trading is False:
                    return

                self.orderID = self.auto_close_position(
                    price=(price := self.long_price + self.pay_up),
                    volume=abs(position.net_position),
                    symbol=self.vtSymbol,
                    exchange=self.exchange,
                    order_direction="buy"
                )
                self.output(f'买入平仓信号价格: {price}')

    def onTrade(self, trade, log=True):
        """成交回调"""
        self.output('成交周期：',self.kline_style)
        super().onTrade(trade, log)

    def onStop(self):
        if self.kline_generator:
            self.kline_generator.stop_push_scheduler()
        super().onStop()